﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace KAImage
{
    /// <summary>
    /// 直方图均衡化 直方图均衡化就是对图像进行非线性拉伸，重新分配图像像素值，使一定灰度范围内的像素数量大致相同
    /// 增大对比度，从而达到图像增强的目的。是图像处理领域中利用图像直方图对对比度进行调整的方法
    /// </summary>

    /// <summary>
    /// 图像增强算法
    /// </summary>
    public unsafe class ImageEnhancement
    {
        /// <summary>
        /// 直方图均衡化算法(对所有通道进行统一处理)
        /// </summary>
        /// <param name="Bmp"></param>
        public static void HistogramEqualize(Bitmap Bmp)
        {
            if (Bmp == null)
                return;
            BitmapData BmpData = Bmp.LockBits(new Rectangle(0, 0, Bmp.Width, Bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int Width, Height, Stride, X, Y, Num;
            byte* Pointer, Scan0;
            int[] HistGram = new int[256];
            byte[] Lut = new byte[256];
            Width = Bmp.Width;
            Height = Bmp.Height;
            Stride = BmpData.Stride;
            Scan0 = (byte*)BmpData.Scan0;
            for (Y = 0; Y < Height; Y++)
            {
                Pointer = Scan0 + Y * Stride;               // 定位到每个扫描行的第一个像素，以避免溶于数据的影响
                for (X = 0; X < Width; X++)
                {
                    HistGram[*Pointer]++;                   // Blue
                    HistGram[*(Pointer + 1)]++;             // Green
                    HistGram[*(Pointer + 2)]++;             // Red    
                    Pointer += 3;                           // 移向下一个像素
                }
            }
            Num = 0;
            for (Y = 0; Y < 256; Y++)
            {
                Num = Num + HistGram[Y];
                Lut[Y] = (byte)((float)Num / (Width * Height * 3) * 255);       // 计算映射表
            }
            for (Y = 0; Y < Height; Y++)
            {
                Pointer = Scan0 + Y * Stride;
                for (X = 0; X < Width * 3; X += 3)          //  也可以这样写
                {
                    Pointer[X] = Lut[Pointer[X]];
                    Pointer[X + 1] = Lut[Pointer[X + 1]];
                    Pointer[X + 2] = Lut[Pointer[X + 2]];
                }
            }
            Bmp.UnlockBits(BmpData);
        }

        /// <summary>
        /// 直方图均衡化算法(对各自单通道进行分别处理)
        /// </summary>
        /// <param name="dstBmp"></param>
        public static void HistogramEqualizeS(Bitmap dstBmp)
        {
            if (dstBmp == null)
            {
                return;
            }
            int[] histogramArrayR = new int[256];//各个灰度级的像素数R
            int[] histogramArrayG = new int[256];//各个灰度级的像素数G
            int[] histogramArrayB = new int[256];//各个灰度级的像素数B
            int[] tempArrayR = new int[256];
            int[] tempArrayG = new int[256];
            int[] tempArrayB = new int[256];
            byte[] pixelMapR = new byte[256];
            byte[] pixelMapG = new byte[256];
            byte[] pixelMapB = new byte[256];
            Rectangle rt = new Rectangle(0, 0, dstBmp.Width, dstBmp.Height);
            BitmapData bmpData = dstBmp.LockBits(rt, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            //统计各个灰度级的像素个数
            for (int i = 0; i < bmpData.Height; i++)
            {
                byte* ptr = (byte*)bmpData.Scan0 + i * bmpData.Stride;
                for (int j = 0; j < bmpData.Width; j++)
                {
                    histogramArrayB[*(ptr + j * 3)]++;
                    histogramArrayG[*(ptr + j * 3 + 1)]++;
                    histogramArrayR[*(ptr + j * 3 + 2)]++;
                }
            }
            //计算各个灰度级的累计分布函数
            for (int i = 0; i < 256; i++)
            {
                if (i != 0)
                {
                    tempArrayB[i] = tempArrayB[i - 1] + histogramArrayB[i];
                    tempArrayG[i] = tempArrayG[i - 1] + histogramArrayG[i];
                    tempArrayR[i] = tempArrayR[i - 1] + histogramArrayR[i];
                }
                else
                {
                    tempArrayB[0] = histogramArrayB[0];
                    tempArrayG[0] = histogramArrayG[0];
                    tempArrayR[0] = histogramArrayR[0];
                }
                //计算累计概率函数，并将值放缩至0~255范围内
                pixelMapB[i] = (byte)(255.0 * tempArrayB[i] / (bmpData.Width * bmpData.Height) + 0.5);//加0.5为了四舍五入取整
                pixelMapG[i] = (byte)(255.0 * tempArrayG[i] / (bmpData.Width * bmpData.Height) + 0.5);
                pixelMapR[i] = (byte)(255.0 * tempArrayR[i] / (bmpData.Width * bmpData.Height) + 0.5);
            }
            //映射转换
            for (int i = 0; i < bmpData.Height; i++)
            {
                byte* ptr = (byte*)bmpData.Scan0 + i * bmpData.Stride;
                for (int j = 0; j < bmpData.Width; j++)
                {
                    *(ptr + j * 3) = pixelMapB[*(ptr + j * 3)];
                    *(ptr + j * 3 + 1) = pixelMapG[*(ptr + j * 3 + 1)];
                    *(ptr + j * 3 + 2) = pixelMapR[*(ptr + j * 3 + 2)];
                }
            }
            dstBmp.UnlockBits(bmpData);
        }
    }
}
